package studyguide.ch19;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.StringItem;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.MetaDataControl;
import javax.microedition.media.control.RecordControl;
import javax.microedition.media.control.VideoControl;

public class MediaRecordForm extends Form {

	private final MobileMediaMidlet parent;
	private final Command backCommand;
	
	private final StringItem noVideo;
	private final StringItem recordButton;
	private final StringItem stopButton;
	private final StringItem status;
	private final StringItem metadata;
	private final StringItem noVideoPlayback;
	
	private Player player;
	private Player copyPlayer;
	private ByteArrayOutputStream captured;
	
	private class MMCommandListener implements CommandListener {
		public void commandAction(Command c, Displayable d) {
			if (c == backCommand) {
				player.close();
				parent.showMainScreen();
			} else {
				throw new RuntimeException("UNKNOWN COMMAND:" + c);
			}
		}
	}
	
	private class PlayCommandListener implements ItemCommandListener {
		public void commandAction(Command c, Item item) {
			try {
				if (item == recordButton) {
					// If not already playing, start to play:
					player.start();
					RecordControl recordControl = (RecordControl) player.getControl("RecordControl");
					if (recordControl != null) {
						captured = new ByteArrayOutputStream();
						recordControl.setRecordStream(captured);
						recordControl.startRecord();
					} else {
						status.setText("RECORD CONTROL NOT AVAILABLE!!!");
					}
				} else if (item == stopButton) {
					// Stop playback and finish recording
					RecordControl recordControl = (RecordControl) player.getControl("RecordControl");
					if (recordControl != null) {
						recordControl.stopRecord();
						recordControl.commit();
						player.stop();
						// Plays the copy:
						ByteArrayInputStream contents = new ByteArrayInputStream(captured.toByteArray());
						copyPlayer = Manager.createPlayer(contents, recordControl.getContentType());
						copyPlayer.realize();
						VideoControl copyVC = (VideoControl) copyPlayer.getControl("VideoControl");
						if (copyVC != null) {
							Item videoItem = (Item) copyVC.initDisplayMode(
									VideoControl.USE_GUI_PRIMITIVE, 
									"javax.microedition.lcdui.Item");
							set(5, videoItem);
						} else {
							if (get(5) != noVideoPlayback) {
								set(5, noVideoPlayback);
							}
						}
						status.setText("Playback started");
						copyPlayer.addPlayerListener(new PlayerListener() {
							public void playerUpdate(Player player,
									String event, Object eventData) {
								if (END_OF_MEDIA.equals(event)) {
									status.setText("Playback finished");
								}
							}
						});
						
						copyPlayer.start();
					} else {
						player.stop();
					}
				} else {
					throw new RuntimeException("Unknown item:" + item);
				}
			} catch (MediaException e) {
				throw new RuntimeException("Error:" + e);
			} catch (IOException e) {
				throw new RuntimeException("Error:" + e);
			}
		}
	}
	
	public MediaRecordForm(MobileMediaMidlet parent) {
		super("Media Details");
		this.parent = parent;
		
		backCommand = new Command("Back", Command.BACK, 1);
		
		PlayCommandListener itemCL = new PlayCommandListener();
		
		noVideo = new StringItem("", "No video");
		noVideoPlayback = new StringItem("", "No video");
		
		recordButton = new StringItem("", "record", StringItem.BUTTON);
		recordButton.setDefaultCommand(new Command("play", Command.ITEM, 1));
		recordButton.setItemCommandListener(itemCL);
		
		stopButton = new StringItem("", "stop", StringItem.BUTTON);
		stopButton.setDefaultCommand(new Command("stop", Command.ITEM, 1));
		stopButton.setItemCommandListener(itemCL);
		
		status = new StringItem("Status:", "");
		metadata = new StringItem("Info:", "");
		
		addCommand(backCommand);
		setCommandListener(new MMCommandListener());
		
		append(noVideo);
		append(recordButton);
		append(stopButton);
		append(status);
		append(metadata);
		append(noVideoPlayback);
	}

	public void initialize(final String uri) {
		status.setText("initializing...");
		Thread thread = new Thread(new Runnable() {
			public void run() {
				try { 
					player = Manager.createPlayer(uri);
					player.prefetch();
					status.setText("Ready");
					
					// Load metadata:
					MetaDataControl metaDataControl = (MetaDataControl) player.getControl("MetaDataControl");
					StringBuffer mdBuffer = new StringBuffer();
					if (metaDataControl != null) {
						String[] keys = metaDataControl.getKeys();
						for (int i = 0; i < keys.length; i++) {
							String key = keys[i];
							mdBuffer.append(key);
							mdBuffer.append(" : ");
							mdBuffer.append(metaDataControl.getKeyValue(key));
							mdBuffer.append("\n");
						}
					} else {
						mdBuffer.append("Metadata not available for this file");
					}
					metadata.setText(mdBuffer.toString());
					
					// Load video, if available
					final VideoControl videoControl = (VideoControl) player.getControl("VideoControl");
					if (videoControl != null) {
						Item item = (Item) videoControl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null);
						set(0, item);
					} else {
						if (get(0) != noVideo) {
							set(0, noVideo);
						}
					}
					
					// Since it's a capture resource, it should 
					// constantly be displaying the output:
					player.start();
				} catch (IOException e) {
					status.setText("Error:" + e);
				} catch (MediaException e) {
					status.setText("Error:" + e);
				}
			}
		});
		thread.start();
	}
	
}
